package main

import (
	"context"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"image"
	"image/jpeg"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/wailsapp/wails/v2/pkg/runtime"
)

// App struct
type App struct {
	ctx context.Context
}

// NewApp creates a new App application struct
func NewApp() *App {
	return &App{}
}

// startup is called when the app starts. The context is saved
// so we can call the runtime methods
func (a *App) startup(ctx context.Context) {
	a.ctx = ctx
}

// Greet returns a greeting for the given name
func (a *App) Greet(name string) string {
	return fmt.Sprintf("Hello %s, It's show time!", name)
}

// 选择文件夹
func (a *App) ChooseFolder() string {
	folder, err := runtime.OpenDirectoryDialog(a.ctx, runtime.OpenDialogOptions{
		Title: "选择文件夹",
	})
	if err != nil {
		return fmt.Sprintf("err %s!", err)
	}
	return folder
}

type FileMD5 struct {
	FileName string `json:"file_name"`
	MD5      string `json:"md5"`
	NewMD5   string `json:"new_md5"`
	Path     string `json:"path"`
}

type GetImageFilesResponse struct {
	Folder string    `json:"folder"`
	Files  []FileMD5 `json:"files"`
}

// 获取文件夹下的所有图片文件
func (a *App) GetImageFiles() *GetImageFilesResponse {
	dir, err := runtime.OpenDirectoryDialog(a.ctx, runtime.OpenDialogOptions{
		Title: "选择文件夹",
	})
	if err != nil {
		return nil
	}

	var files []FileMD5

	if dir == "" {
		return nil
	}

	f, err := os.Open(dir)
	if err != nil {
		return nil
	}
	fileInfo, err := f.Readdir(-1)
	defer f.Close()
	if err != nil {
		return nil
	}
	for _, file := range fileInfo {
		if !file.IsDir() {
			if isImageFile(file.Name()) {
				md5, err := md5sum(dir + "/" + file.Name())
				if err != nil {
					return nil
				}
				files = append(files, FileMD5{FileName: file.Name(), MD5: md5, Path: dir + "/" + file.Name()})
			}
		}
	}
	return &GetImageFilesResponse{Folder: dir, Files: files}
}

// 计算文件的MD5值
func md5sum(file string) (string, error) {
	f, err := os.Open(file)
	if err != nil {
		return "", err
	}
	defer f.Close()

	h := md5.New()
	if _, err := io.Copy(h, f); err != nil {
		return "", err
	}

	return hex.EncodeToString(h.Sum(nil)), nil
}

// 判断文件是否为图片文件
func isImageFile(file string) bool {
	ext := strings.ToLower(filepath.Ext(file))
	return ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif"
}

type UpdateMd5Request struct {
	OutputFolder string    `json:"output_folder"`
	Files        []FileMD5 `json:"files"`
}

// 修改md5值
func (a *App) CalculateMD5(data *UpdateMd5Request) *[]FileMD5 {
	if _, err := os.Stat(data.OutputFolder); os.IsNotExist(err) {
		err := os.MkdirAll(data.OutputFolder, 0755)
		if err != nil {
			log.Fatal(err)
		}
	}
	var files []FileMD5
	for _, file := range data.Files {
		_file, err := os.Open(file.Path)
		if err != nil {
			panic(err)
		}
		defer _file.Close()

		img, _, err := image.Decode(_file)
		if err != nil {
			panic(err)
		}

		out, err := os.Create(data.OutputFolder + "/" + file.FileName)
		if err != nil {
			panic(err)
		}
		defer out.Close()

		options := jpeg.Options{
			Quality: 100, // 设置不同的质量将改变图片数据
		}

		err = jpeg.Encode(out, img, &options)
		if err != nil {
			panic(err)
		}

		newFile, err := os.Open(data.OutputFolder + "/" + file.FileName)
		if err != nil {
			panic(err)
		}
		defer newFile.Close()

		hash := md5.New()
		if _, err := io.Copy(hash, newFile); err != nil {
			log.Fatal(err)
		}

		hashInBytes := hash.Sum(nil)[:16]
		newMD5 := hex.EncodeToString(hashInBytes)
		files = append(files, FileMD5{FileName: file.FileName, MD5: file.MD5, NewMD5: newMD5, Path: file.Path})
	}
	return &files
}
